package com.icesoft.base.manager.controller.security.monitor;

import com.icesoft.core.common.helper.Resp;
import com.icesoft.core.web.configurer.test.condition.ConditionOnNotMockTestCase;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.hibernate.SessionFactory;
import org.hibernate.cache.internal.EnabledCaching;
import org.springframework.web.bind.annotation.*;

import javax.cache.CacheManager;
import javax.cache.configuration.CompleteConfiguration;
import javax.cache.expiry.Duration;
import javax.cache.expiry.ExpiryPolicy;
import javax.persistence.EntityManagerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;

/**
 * 缓存管理接口
 */
@RestController
@RequestMapping("security/cache")
@ConditionOnNotMockTestCase
@Slf4j
@AllArgsConstructor
public class AdminCacheMonitorController {

    private CacheManager cacheManager;

    private EntityManagerFactory entityManagerFactory;

    /**
     * 获取所有缓存名
     */
    @GetMapping("cacheNames")
    public Resp<List<String>> cacheMonitor() {
        return Resp.success(Lists.newArrayList(cacheManager.getCacheNames().iterator()));
    }

    /**
     * 根据缓存名查询缓存
     */
    @GetMapping("cachePage")
    public PageDTO<CacheDTO> cachePage(@RequestParam String cacheName, @RequestParam int offset,
                                       @RequestParam int limit) {
        int total = 0;
        List<CacheDTO> data = new ArrayList<>(10);

        int endRow = offset + limit;
        CompleteConfiguration<Object, Object> configuration = cacheManager.getCache(cacheName).getConfiguration(CompleteConfiguration.class);
        ExpiryPolicy expiryPolicy = configuration.getExpiryPolicyFactory().create();
        Duration duration = expiryPolicy.getExpiryForCreation();
        if (duration == null || duration.getTimeUnit() == null) {
            duration = expiryPolicy.getExpiryForUpdate();
            if (duration == null || duration.getTimeUnit() == null) {
                duration = expiryPolicy.getExpiryForAccess();
            }
        }
        long expireTime = duration == null ? 0 : TimeUnit.MINUTES.convert(duration.getDurationAmount(), duration.getTimeUnit());
        for (javax.cache.Cache.Entry<Object, Object> cache : cacheManager.getCache(cacheName)) {
            try {
                total++;
                if (total >= offset && total < endRow) {
                    data.add(new CacheDTO(expireTime, cache.getKey().toString(), cache.getValue().toString()));
                }
            } catch (NoSuchElementException ignored) {
            }
        }
        PageDTO<CacheDTO> pageDTO = new PageDTO<>();
        pageDTO.setTotal(total);
        pageDTO.setData(data);
        return pageDTO;
    }

    @Data
    public static class PageDTO<T> {

        private int total;
        private List<T> data;
    }

    @Data
    @AllArgsConstructor
    private static class CacheDTO {
        long expireTime;
        String key;
        String value;
    }

    /**
     * 清理指定缓存
     */
    @PostMapping("clearCache")
    public Resp<String> clearCache(@RequestParam String cacheName) {
        EnabledCaching enabledCaching = entityManagerFactory.getCache().unwrap(EnabledCaching.class);
        if (enabledCaching.getRegion(cacheName) != null) {
            enabledCaching.evictRegion(cacheName);
            enabledCaching.evictQueryRegions();
        } else {
            cacheManager.getCache(cacheName).removeAll();
        }
        return Resp.success(cacheName);
    }

    /**
     * 清理全部缓存
     */
    @PostMapping("clearAllCache")
    public Resp<String> clearAllCache() {
        for (String cacheName : cacheManager.getCacheNames()) {
            cacheManager.getCache(cacheName).removeAll();
        }
        SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
        sessionFactory.getCache().evictAllRegions();
        return Resp.success("全部缓存清理成功");
    }
}
